<?php

namespace Sharks\Core\Http\Routing;

use Exception;
use Sharks\Core\Support\Base\Precondition;
use Sharks\Core\Support\Base\Str;

/**
 * Route的conf类文件读取类，可以将route规则写在*.conf文件中，而非使用route.php文件
 * conf文件规则：
 *     1. '#'号开头的行为注释，解析时忽略
 *     2. 有效的route行，包括:(1)Http动词;(2)route;(3)action与middleware;(4)可选的说明。 各部分用'\s'，即空格或tab等隔开
 *     3. action与middleware的格式为：moduleName.controllerName@methodName(middlewares). 
 *         其中moduleName为模块名，可选，如没有，则其后的'.'号省略
 *         其中controllerName为对应的controller类名，不可省略
 *         其中methodName为对应的方法名，前置一下'@'号，都不可省略
 *         其中middlewares为中间件的名称集合，各中间件之间用','号相隔，且用'()'括号与其它部分相隔，如没有，则可以省略
 *     example:
 *         <code>
 *         # 前台页面 
 *         GET  /login          Main@login                  用户登陆
 *         POST /login          Main@loginForm              用户登陆操作
 *
 *         # 系统用户列表 
 *         GET  /admin/users    Sysuser@users(kernel.auth)  系统用户列表   
 *         </code>
 */
class RouteConfReader {

    /**
     * 读取route.conf文件，并解析为route
     * @param  [type] $filePath [description]
     * @return [type]           [description]
     */
    public static function read($filePath) {
        $routeCollection = new RouteCollection;

        if (file_exists($filePath)) {

            $file = fopen($filePath, "r");
            $num = 1;
            while(!feof($file)){
                $line = fgets($file);

                list($verb, $route, $action, $middlewares, $desc) = self::resolveLine($line, ++$num);

                try {
                    if (!empty($verb)) {
                        $routeCollection->register($verb, $route, $action, $middlewares, $desc);
                    }
                }
                catch (Exception $e) {
                    $msg = $e->getMessage();
                    throw new \InvalidArgumentException("route.conf $msg #line:$num");
                }
            }
            fclose($file);
        }

        return $routeCollection;
    }

    public static function resolveLine($line, $num = 1) {
        if (empty($line) || Str::isBlank($line)) {
            return;
        }
        // 按行读取
        $line = trim($line);
        if (Str::startsWith($line, '#')) {//如果以'#'开头,则为注释
            return;
        }
        else {
            $vars = preg_split('/\s+/', $line);
            Precondition::check(count($vars) > 2 && count($vars) < 5, "route.conf 文件格式不对 参数数目不正确 #line:$num");

            $verb = $vars[0];
            $route = $vars[1];
            $action = $vars[2];
            $desc = (count($vars) == 4) ? $vars[3] : null;
            $middlewares = array();
            if (strpos($action, '(') > 0) {
                $temp = explode('(', $action);
                $middlewares = explode(',', rtrim($temp[1], ')'));
                $action = $temp[0];
            }

            return array($verb, $route, $action, $middlewares, $desc);
        }
    }
}